/*
 * TreeDelegate.cpp  0.4.0 / Nov 30, 2010
 *
 * Copyright (c) 2010 - 2011, cute4j.com and contributors.
 *
 * This software is licensed under the LGPL version 2.1 license.
 * A copy of this license is included in the file LICENSE-LGPL.txt.
 */
#include "TreeDelegate.h"

#include "QCursorAdapter.h"

// TreeDelegate :: Protected Constructor. --------------------------------------

/*!
 * \brief Constructs new TreeDelegate object.
 *
 * \param env the JNIEnv pointer
 * \param obj the Tree java object
 */
TreeDelegate::TreeDelegate(JNIEnv *env, jobject obj)
  : ComponentDelegate(env, obj, new QTreeViewAdapter(this)), m_nodeIcon(0),
    m_treeModel(0), m_treeSelectionModel(0)
{
  // empty constructor body
}

// TreeDelegate :: Protected Destructor. ---------------------------------------

/*!
 * \brief Destroys the TreeDelegate object.
 */
TreeDelegate::~TreeDelegate()
{
  if (m_nodeIcon) {
    delete m_nodeIcon;
  }
  if (m_treeSelectionModel) {
    delete m_treeSelectionModel;
  }
  if (m_treeModel) {
    delete m_treeModel;
  }
}

// TreeDelegate :: Native Calls. -----------------------------------------------

/*!
 * \brief Creates icon.
 *
 * \param env the JNIEnv pointer
 * \param iconSet the icon set
 */
void TreeDelegate::createIcon(JNIEnv *env, jobject iconSet)
{
  Q_ASSERT(env);
  Q_ASSERT(iconSet);
  SWING_REENTRANT(createIcon, SWING_ENV_ARG, JOBJECT_ARG(iconSet))
  m_nodeIcon = new QIconAdapter(env, iconSet);
}

/*!
 * \brief Sets whether or not the tree is using tree model.
 *
 * \param env the JNIEnv pointer
 * \param useModel \c true if using
 */
void TreeDelegate::setUseModel(JNIEnv *env, jboolean useModel)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setUseModel, SWING_ENV_ARG, JBOOLEAN_ARG(useModel))
  TreeModel *oldTreeModel = m_treeModel;
  QItemSelectionModel *oldTreeSelectionModel = m_treeSelectionModel;
  if (useModel) {
    m_treeModel = new TreeModel(this);
    m_treeSelectionModel = new QItemSelectionModel(m_treeModel);
    qTreeView()->setModel(m_treeModel);
    qTreeView()->setSelectionModel(m_treeSelectionModel);
    connect(m_treeSelectionModel,
            SIGNAL(selectionChanged(const QItemSelection &,
                                    const QItemSelection &)),
            SLOT(selectionChangedSlot(const QItemSelection &,
                                      const QItemSelection &)));
    qTreeView()->expandToDepth(0); // TODO: temp
    qTreeView()->resizeColumnToContents(0);
  } else {
    qTreeView()->setSelectionModel(0);
    qTreeView()->setModel(0);
  }
  if (oldTreeSelectionModel) {
    delete oldTreeSelectionModel;
  }
  if (oldTreeModel) {
    disconnect(oldTreeModel,
               SIGNAL(selectionChanged(const QItemSelection &,
                                       const QItemSelection &)),
               SLOT(selectionChangedSlot(const QItemSelection &,
                                         const QItemSelection &)));
    delete oldTreeModel;
  }
}

// TreeDelegate :: Static Native Calls. ----------------------------------------

/*!
 * \brief Initializes the TreeDelegate class.
 *
 * \param env the JNIEnv pointer
 * \param cls the Tree java class
 * \param treeNodeClass the ThreeNode class
 *
 * \exception FatalError if failed
 */
void TreeDelegate::initialize(JNIEnv *env, jclass cls, jclass treeNodeClass)
{
  Q_ASSERT(env);
  Q_ASSERT(cls);
  Q_ASSERT(!sm_getRootNodeMID);
  TreeNode::initialize(env, treeNodeClass);
  if (!INIT_UMID(getRootNode, cls,
                 "()Lcom/cute4j/swing/tree/TreeNode;") ||
      !INIT_UMID(setNodeIcon, cls,
                 "(Lcom/cute4j/swing/tree/TreeNode;)Z") ||
      !INIT_UMID(nodeSelected, cls,
                 "(Lcom/cute4j/swing/tree/TreeNode;)V")) {
    FATAL_LOGGED_ERROR("TreeDelegate initialization failed");
  }
}

/*!
 * \brief Returns new instance of the delegate object
 *
 * \param env the JNIEnv pointer
 * \param obj the Swing object
 * 
 * \return new instance of the delegate object
 */
jlong TreeDelegate::newInstance(JNIEnv *env, jobject obj)
{
  if (JNISwingWrapper::isSwingThread(env)) {
    return reinterpret_cast<jlong>(new TreeDelegate(env, obj));
  }
  return SwingUtilitiesDelegate::invokeLongAndWait(env, obj, createMID());
}

// TreeDelegate :: Native Callbacks. -------------------------------------------

/*!
 * \brief Returns root node.
 * 
 * \return root node
 */
jobject TreeDelegate::getRootNode()
{
  jobject result;
  if (jniObject()->callObjectMethod(result, sm_getRootNodeMID)) {
    return result;
  }
  return 0;
}

/*!
 * \brief Calls \c nodeSelected method of the tree object.
 *
 * \param node the node
 */
void TreeDelegate::nodeSelected(jobject node)
{
  jniObject()->callVoidMethod(sm_nodeSelectedMID, node);
}

/*!
 * \brief Calls \c setNodeIcon method of the tree object.
 *
 * \param node the node
 */
jboolean TreeDelegate::setNodeIcon(jobject node)
{
  jboolean result;
  if (jniObject()->callBooleanMethod(result, sm_setNodeIconMID, node)) {
    return result;
  }
  return false;
}

// TreeDelegate :: Public Member Functions. ------------------------------------

/*!
 * \brief Returns the icon for the specified node.
 *
 * \param node the node
 *
 * \return the icon for the specified node.
 */
QIcon *TreeDelegate::getNodeIcon(jobject node)
{
  Q_ASSERT(node);
  if (setNodeIcon(node)) {
    return m_nodeIcon;
  }
  return 0;
}

// TreeDelegate :: Overridden Member Functions. --------------------------------

/*!
 * \inheritDoc
 */
jobject TreeDelegate::getBackground(JNIEnv *env, jclass colorClass)
{
  return QColorAdapter::toJColor(env, colorClass,
                        qTreeView()->viewport()->palette().color(
                                    qTreeView()->viewport()->backgroundRole()));
}

/*!
 * \inheritDoc
 */
void TreeDelegate::setBackground(JNIEnv *env, jint argb)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setBackground, SWING_ENV_ARG, JINT_ARG(argb))
  QColorAdapter color(argb);
  QPalette palette(qTreeView()->viewport()->palette());
  if (color.isValid()) {
    palette.setColor(qTreeView()->viewport()->backgroundRole(), color);
  } else {
    palette.setColor(qTreeView()->viewport()->backgroundRole(),
                     QApplication::palette().color(
                                   qTreeView()->viewport()->backgroundRole()));
  }
  qTreeView()->viewport()->setPalette(palette);
}

/*!
 * \inheritDoc
 */
void TreeDelegate::setNullBackground(JNIEnv *env)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setNullBackground, SWING_ENV_ARG)
  QPalette palette(qTreeView()->viewport()->palette());
  palette.setColor(qTreeView()->viewport()->backgroundRole(),
                   QApplication::palette().color(
                                 qTreeView()->viewport()->backgroundRole()));
  qTreeView()->viewport()->setPalette(palette);
}

/*!
 * \inheritDoc
 */
jint TreeDelegate::getCursor(JNIEnv *env)
{
  Q_UNUSED(env);
  return QCursorAdapter::cursorType(qTreeView()->viewport()->cursor());
}

/*!
 * \inheritDoc
 */
void TreeDelegate::setCursor(JNIEnv *env, jint type)
{
  Q_ASSERT(env);
  SWING_REENTRANT(setCursor, SWING_ENV_ARG, JINT_ARG(type))
  if (type < 0) {
    qTreeView()->viewport()->unsetCursor();
  } else {
    qTreeView()->viewport()->setCursor(QCursorAdapter(type));
  }
}

// TreeDelegate :: Protected Member Function. ----------------------------------

/*!
 * \brief \c selectionChanged slot.
 *
 * \param selected the selected item
 * \param deselected the deselected item
 */
void TreeDelegate::selectionChangedSlot(const QItemSelection &selected,
                                        const QItemSelection &deselected)
{
  Q_UNUSED(deselected);
  if (!selected.empty()) {
    // Qt Bug ???
    //QModelIndexList items = qTreeView()->selectionModel()->selectedIndexes();
    QModelIndex index = selected.at(0).topLeft();
    if (index.isValid()) {
      TreeNode *node = static_cast<TreeNode *>(index.internalPointer());
      if (node) {
        nodeSelected(node->node());
      }
    }
  }
}

// TreeDelegate :: Private Static Data Members. --------------------------------

jmethodID TreeDelegate::sm_getRootNodeMID = 0;
jmethodID TreeDelegate::sm_setNodeIconMID = 0;
jmethodID TreeDelegate::sm_nodeSelectedMID = 0;
